<template>
  <div class="sankey-container">
    <!-- 桑基图容器 -->
    <div ref="sankeySvg" class="sankey-svg"></div>

    <!-- 图例部分 -->
    <div class="legend">
      <div class="legend-item">
        <div class="color-box" style="background-color: #4e79a7;"></div>
        <span>首页访问</span>
      </div>
      <div class="legend-item">
        <div class="color-box" style="background-color: #f28e2c;"></div>
        <span>产品列表页</span>
      </div>
      <div class="legend-item">
        <div class="color-box" style="background-color: #e15759;"></div>
        <span>产品详情页</span>
      </div>
      <div class="legend-item">
        <div class="color-box" style="background-color: #76b7b2;"></div>
        <span>购物车</span>
      </div>
      <div class="legend-item">
        <div class="color-box" style="background-color: #59a14f;"></div>
        <span>支付</span>
      </div>
      <div class="legend-item">
        <div class="color-box" style="background-color: #f8efcf;"></div>
        <span>完成订单</span>
      </div>
    </div>

    <!-- 统计信息展示 -->
    <div class="stats">
      <div class="stat-item">
        <span class="stat-value">{{ conversionRate }}%</span>
        <span class="stat-label">整体转化率</span>
      </div>
      <div class="stat-item">
        <span class="stat-value">{{ totalVisits }}</span>
        <span class="stat-label">总访问量</span>
      </div>
      <div class="stat-item">
        <span class="stat-value">{{ completedOrders }}</span>
        <span class="stat-label">完成订单</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import * as d3 from 'd3';
import { sankey as d3Sankey, sankeyLinkHorizontal } from 'd3-sankey';
import { ref, onMounted, computed } from 'vue';
import { sankeyData } from '../data/sample-data';

// 桑基图的 SVG 容器引用
const sankeySvg = ref(null);

// 图表数据，使用深拷贝避免修改原始数据
const chartData = ref({ ...sankeyData });

// 计算总访问量（从第一个链接的值获取）
const totalVisits = computed(() => {
  return chartData.value.links[0].value;
});

// 计算完成订单数量（找到连接到“完成订单”节点的流量）
const completedOrders = computed(() => {
  const targetNode = chartData.value.nodes.find(node => node.name === '完成订单');
  if (!targetNode) return 0;

  return chartData.value.links
      .filter(link => link.target === targetNode.id)
      .reduce((sum, link) => sum + link.value, 0);
});

// 计算转化率（完成订单 / 总访问量）
const conversionRate = computed(() => {
  return ((completedOrders.value / totalVisits.value) * 100).toFixed(2);
});

// 初始化图表函数
const initChart = () => {
  if (!sankeySvg.value) return;

  // 清除现有内容
  d3.select(sankeySvg.value).selectAll("*").remove();

  const width = sankeySvg.value.clientWidth;
  const height = Math.max(500, window.innerHeight * 0.6);

  const svg = d3.select(sankeySvg.value)
      .append("svg")
      .attr("width", width)
      .attr("height", height)
      .attr("viewBox", [0, 0, width, height])
      .attr("style", "max-width: 100%; height: auto;");

  // 颜色方案
  const color = d3.scaleOrdinal(d3.schemeTableau10);

  // 桑基图布局配置
  const sankeyGenerator = d3Sankey()
      .nodeId(d => d.id)
      .nodeWidth(15)
      .nodePadding(10)
      .extent([[20, 20], [width - 20, height - 50]]);

  // 处理数据
  const graph = sankeyGenerator({
    nodes: chartData.value.nodes.map(d => ({ ...d })),
    links: chartData.value.links.map(d => ({ ...d, value: +d.value }))
  });

  // 添加连接路径
  const link = svg.append("g")
      .attr("class", "links")
      .attr("fill", "none")
      .attr("stroke-opacity", 0.3)
      .selectAll("path")
      .data(graph.links)
      .join("path")
      .attr("d", sankeyLinkHorizontal())
      .attr("stroke", d => color(d.source.id))
      .attr("stroke-width", d => Math.max(1, d.width))
      .on("mouseover", function(event, d) {
        d3.select(this)
            .attr("stroke-opacity", 0.8)
            .attr("stroke-width", d.width + 2);

        tooltip
            .style("opacity", 1)
            .html(`<div>${d.source.name} → ${d.target.name}</div>
               <div>流量: ${d.value} (${(d.value / d.source.value * 100).toFixed(1)}%)</div>`)
            .style("left", (event.pageX + 10) + "px")
            .style("top", (event.pageY - 28) + "px");
      })
      .on("mouseout", function() {
        d3.select(this)
            .attr("stroke-opacity", 0.3)
            .attr("stroke-width", d => d.width);
        tooltip.style("opacity", 0);
      });

  // 添加节点矩形
  const node = svg.append("g")
      .attr("class", "nodes")
      .attr("font-family", "sans-serif")
      .attr("font-size", 10)
      .selectAll("g")
      .data(graph.nodes)
      .join("g");

  node.append("rect")
      .attr("x", d => d.x0)
      .attr("y", d => d.y0)
      .attr("height", d => d.y1 - d.y0)
      .attr("width", d => d.x1 - d.x0)
      .attr("fill", d => color(d.id))
      .attr("stroke", "#000")
      .on("mouseover", function(event, d) {
        d3.select(this).attr("stroke-width", 2).attr("opacity", 0.9);
        tooltip
            .style("opacity", 1)
            .html(`<div>${d.name}</div>
               <div>总流量: ${d.value}</div>`)
            .style("left", (event.pageX + 10) + "px")
            .style("top", (event.pageY - 28) + "px");
      })
      .on("mouseout", function(event, d) {
        d3.select(this).attr("stroke-width", 1).attr("opacity", 1);
        tooltip.style("opacity", 0);
      });

  // 添加节点标签
  node.append("text")
      .attr("x", d => d.x0 - 6)
      .attr("y", d => (d.y1 + d.y0) / 2)
      .attr("dy", "0.35em")
      .attr("text-anchor", "end")
      .attr("fill", "#555")
      .attr("font-weight", "bold")
      .text(d => d.name)
      .filter(d => d.x0 < width / 2)
      .attr("x", d => d.x1 + 6)
      .attr("text-anchor", "start");

  // 添加标题
  svg.append("text")
      .attr("x", width / 2)
      .attr("y", 20)
      .attr("text-anchor", "middle")
      .attr("font-size", "16px")
      .attr("font-weight", "bold")
      .text("电商用户转化路径分析");

  // 添加工具提示
  const tooltip = d3.select(sankeySvg.value)
      .append("div")
      .attr("class", "sankey-tooltip")
      .style("opacity", 0);
};

// 重置图表函数
const resetChart = () => {
  chartData.value = { ...sankeyData };
  initChart();
};

// 窗口调整大小时重新渲染图表
const handleResize = () => {
  initChart();
};

// 生命周期钩子：组件挂载后初始化图表并监听窗口大小变化
onMounted(() => {
  initChart();
  window.addEventListener('resize', handleResize);
});
</script>

<style scoped>
.sankey-container {
  position: relative;
  width: 100%;
  padding: 20px;
  background-color: #f8fafc;
  border-radius: 10px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.sankey-svg {
  width: 100%;
  min-height: 500px;
  margin-bottom: 20px;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  background-color: #fff;
  position: relative;
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  margin-bottom: 20px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.color-box {
  width: 16px;
  height: 16px;
  border-radius: 3px;
}

.stats {
  display: flex;
  gap: 30px;
  padding: 15px;
  background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
  border-radius: 8px;
  color: white;
}

.stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.stat-value {
  font-size: 28px;
  font-weight: 700;
  margin-bottom: 5px;
}

.stat-label {
  font-size: 14px;
  opacity: 0.9;
}
</style>
